package com.sh.data.engine.domain.dataasset.job;

import com.sh.data.engine.common.constants.Constants;
import com.sh.data.engine.domain.common.service.CommonService;
import com.sh.data.engine.domain.shims.db.BaseDbManager;
import com.sh.data.engine.domain.shims.db.model.TableSizeDomain;
import com.sh.data.engine.domain.workspace.index.model.domain.ProjectDomain;
import com.sh.data.engine.domain.workspace.index.service.ProjectService;
import com.sh.data.engine.job.core.context.XxlJobHelper;
import com.sh.data.engine.job.core.handler.annotation.XxlJob;
import com.sh.data.engine.repository.dao.workspace.manager.entity.StorageEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: zigui.zdf @Date: 2022/2/25 11:25:01 @Description: 同步表大小到redis中，每5分钟执行一次
 */
@Component
@Slf4j
public class SyncTblSizeToRedisTask {

    @Autowired
    private ProjectService projectService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private RedisTemplate redisTemplate;

    @XxlJob("SyncTblSizeToRedisTask")
    public void run() {
        final List<ProjectDomain> projectDomains = projectService.getAllProject();

        if (CollectionUtils.isEmpty(projectDomains)) {
            XxlJobHelper.log("当前工作空间数量为0，本次同步结束...");
            return;
        }

        XxlJobHelper.log("当前工作空间数量为：{}", projectDomains.size());

        for (ProjectDomain projectDomain : projectDomains) {
            XxlJobHelper.log("正在同步：[{}]空间内的表大小", projectDomain.getName());

            long s = System.currentTimeMillis();

            try {

                run1(projectDomain.getId());

                XxlJobHelper.log(
                    "[{}]空间内的表大小计算结束，耗时:[{}]ms", projectDomain.getName(), System.currentTimeMillis() - s);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                XxlJobHelper.log(
                    "[{}]空间内的表大小计算异常，耗时:[{}]ms，原因：{}",
                    projectDomain.getName(),
                    System.currentTimeMillis() - s,
                    e.getMessage());
            }
        }
    }

    private void run1(Long projectId) throws SQLException {
        final StorageEntity storage = commonService.getStorage(projectId);

        final BaseDbManager dbManager = projectService.getDbManager(projectId, 10);

        if (null == dbManager || null == storage) {
            XxlJobHelper.log("空间未配置存储，同步结束...");
            return;
        }

        final List<TableSizeDomain> tableSizeList =
            dbManager.getTableSizeList(storage.getRmdbs().getDbName(), storage.getRmdbs().getDbName());

        XxlJobHelper.log("空间内存储中共有:{}张表", tableSizeList.size());

        final Long totalSize = tableSizeList.stream().mapToLong(TableSizeDomain::getTableSize).sum();

        String projectKey = String.format(Constants.RedisKey.PROJECT_STORAGE_SIZE_EXP, projectId);
        redisTemplate.opsForValue().set(projectKey, totalSize);
        Map<String, Long> tableSizeMap = new HashMap<>();

        for (TableSizeDomain tableSizeDomain : tableSizeList) {
            String tableName = tableSizeDomain.getTableName();
            if (StringUtils.isNotBlank(tableSizeDomain.getSchema())) {
                tableName = tableSizeDomain.getSchema() + "." + tableSizeDomain.getTableName();
            }
            tableSizeMap.put(tableName, tableSizeDomain.getTableSize());
        }
        // fix 10w tables network timeout
        redisTemplate
            .opsForHash()
            .putAll(
                String.format(Constants.RedisKey.PROJECT_TABLE_STORAGE_SIZE_EXP, projectId),
                tableSizeMap);
    }
}
